package org.example.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import org.junit.Test;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 类加载器读取：读取类路径下任意位置中的任意资源.
 * 即便是打包成 .jar、.war 包部署到生产环境，照样读取正常。
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2021/4/2 19:29
 */
@RestController
public class ClassLoaderController {

    /**
     * 1、ClassLoader.getResource 方法内部使用 utf-8 对路径信息进行了编码，当路径中存在中文或空格等字符时，就会对它们进行转换，
     * 这样获取路径信息时就会出现 utf-8 编码后的字符，如 '85%ac%e5%bc%80%e9%85%8d%e7%bd'，看起以来就像乱码一样，导致路径不存在。
     * 2、解决办法是使用 URLDecoder.decoder 方法对地址进行解码，以得到原始路径。
     *
     * @throws UnsupportedEncodingException
     */
    @Test
    public void URL2File() throws UnsupportedEncodingException {
        String classPath = "static/完整性技术检查表-20220301.xlsx";
        URL url = ClassLoaderController.class.getClassLoader().getResource(classPath);
        String path = url.getPath();
        String urlFile = url.getFile();

        // /E:/IDEA_Projects/java-se/target/classes/static/%e5%ae%8c%e6%95%b4%e6%80%a7%e6%8a%80%e6%9c%af%e6%a3%80%e6%9f%a5%e8%a1%a8-20220301.xlsx
        System.out.println("path 转码前：" + path);
        // /E:/IDEA_Projects/java-se/target/classes/static/%e5%ae%8c%e6%95%b4%e6%80%a7%e6%8a%80%e6%9c%af%e6%a3%80%e6%9f%a5%e8%a1%a8-20220301.xlsx
        System.out.println("urlFile 转码前：" + urlFile);

        path = URLDecoder.decode(path, "utf-8");
        /// 转码后：/E:/IDEA_Projects/java-se/target/classes/static/完整性技术检查表-20220301.xlsx
        System.out.println("path 转码后：" + path);
        File file = new File(path);
        // 转码后：E:\IDEA_Projects\java-se\target\classes\static\完整性技术检查表-20220301.xlsx
        System.out.println("转文件：" + file.exists() + " " + file.getAbsolutePath());
    }

    /**
     * http://localhost:8080/classLoader/findAllByClassPath
     * <p>
     * URL getResource(String name) : 查找类路径下指定名称的资源
     * 1、name ：只要是编译后位于 classed 目录下的任意文件都行，多级时用左斜杠即可，如 config/root/data.xml
     * 2、通常用于读取 resources 资源目录下的资源，然而其实 src/java 源码目录的文件同样可以，只要编译后能到 classes 目录下
     * 3、注意只能是类路径下的，不能是其它位置，也不能是绝对路径，不存在时 getResource 返回 null。
     */
    @GetMapping("classLoader/findAllByClassPath")
    public Map<String, String> findAllByClassPath(String classPath) {
        Map<String, String> stringMap = new HashMap<>();
        classPath = StrUtil.isBlank(classPath) ? "config/config2.properties" : classPath;
        ClassLoader classLoader = ClassLoaderController.class.getClassLoader();

        URL url = classLoader.getResource(classPath);
        Assert.notNull(url, "资源文件不存在！");
        String path1 = url.getPath();
        stringMap.put("path1", path1);

        URL resource = classLoader.getResource("org/example/controller/ClassLoaderController.class");
        String path2 = resource == null ? null : resource.getPath();
        stringMap.put("path2", path2);

        // {
        //     "path1": "/E:/IDEA_Projects/java-se/target/classes/config/config2.properties",
        //      "path2": "/E:/IDEA_Projects/java-se/target/classes/org/example/controller/ClassLoaderController.class"
        // }
        return stringMap;
    }

    /**
     * http://localhost:8080/classLoader/readLinePlan1
     * <p>
     * InputStream getResourceAsStream(String name) ：读取类路径下知道名称的资源，并返回字节输入流
     * 其实底层就是在 getResource 的基础上，加了一个  url.openStream()，所以资源不存在时，返回 null。
     * 注意只能是类路径下的，不能是其它位置，也不能是绝对路径。
     * <p>
     * 使用流的好处是可以读取任何文件的内容，比如图片、音视频等等。
     * 如果是文本文件则推荐使用其它更加简易快捷的方式。cn.hutool.core.io.resource.ResourceUtil
     * <p>
     * 即便是打包成 .jar、.war 包部署到生产环境，照样读取正常。
     */
    @GetMapping("classLoader/readLinePlan1")
    public List<String> readLinePlan1(String classPath) {
        List<String> dataList = new ArrayList<>();
        classPath = StrUtil.isBlank(classPath) ? "config/config2.properties" : classPath;

        ClassLoader classLoader = ClassLoaderController.class.getClassLoader();
        InputStream inputStream = classLoader.getResourceAsStream(classPath);
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        try {
            Assert.notNull(inputStream, "资源文件不存在！");
            inputStreamReader = new InputStreamReader(inputStream, "gbk");
            bufferedReader = new BufferedReader(inputStreamReader);
            StringBuilder sBuilder = new StringBuilder();
            String readLine = bufferedReader.readLine();
            while (readLine != null) {
                dataList.add(readLine);
                sBuilder.append(readLine).append("\n");
                readLine = bufferedReader.readLine();
            }
            /**
             * #.properties 资源文件格式就是简单的 key=value 形式，一行写一个 key-value,换行分割，结尾不要有分号
             * name=root
             * password=123456
             *
             * #资源文件中不推荐有中文，如果 key 有多个 value，可以选择使用特定的分割符连接，代码中再进行 split(分割)
             * color=red,yellow,blue
             */
            System.out.println(sBuilder.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (inputStreamReader != null) {
                    inputStreamReader.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // [
        //   "#.properties 资源文件格式就是简单的 key=value 形式，一行写一个 key-value,换行分割，结尾不要有分号",
        //   "name=root",
        //   "password=123456",
        //   "",
        //   "#资源文件中不推荐有中文，如果 key 有多个 value，可以选择使用特定的分割符连接，代码中再进行 split(分割)",
        //   "color=red,yellow,blue"
        // ]
        return dataList;
    }

    /**
     * http://localhost:8080/classLoader/readLinePlan2
     * <p>
     * 读取 Class 下文件内容
     * 即便是打包成 .jar、.war 包部署到生产环境，照样读取正常。
     * 推荐使用 cn.hutool.core.io.resource.ResourceUtil
     */
    @GetMapping("classLoader/readLinePlan2")
    public List<String> readLinePlan2(String classPath) {
        classPath = StrUtil.isBlank(classPath) ? "config/person.csv" : classPath;

        ClassLoader classLoader = ClassLoaderController.class.getClassLoader();
        URL url = classLoader.getResource(classPath);
        Assert.notNull(url, "资源文件不存在！");
        // 读取文件内容
        String readString = FileUtil.readString(url, "GBK");
        // 序号,姓名,性别,婚否,年龄
        // 1,张三,男,否,29
        // 2,李斯,男,是,33
        // 3,白雪儿,女,否,19
        System.out.println(readString);

        List<String> list = FileUtil.readLines(url, "GBK");
        // [
        //   "序号,姓名,性别,婚否,年龄",
        //   "1,张三,男,否,29",
        //   "2,李斯,男,是,33",
        //   "3,白雪儿,女,否,19"
        // ]
        return list;
    }

}
